// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef LOGIN_MANAGER_SERVER_BACKED_STATE_KEY_GENERATOR_H_
#define LOGIN_MANAGER_SERVER_BACKED_STATE_KEY_GENERATOR_H_

#include <stdint.h>

#include <map>
#include <string>
#include <vector>

#include <base/callback.h>
#include <base/files/file_path.h>
#include <base/macros.h>

#include "login_manager/job_manager.h"

namespace login_manager {

class ChildOutputCollector;
class LoginMetrics;
class SystemUtils;

// Generates time-based opaque device identifiers used as keys in server-side
// device state storage. This allows persisting device-specific data on the
// server that survives device recovery and can be restored afterwards.
//
// Identifiers are generated by running a number of stable hardware identifiers
// along with a quantized time stamp through a cryptographic hash function. The
// resulting identifiers shouldn't be predictable by servers, so it's important
// to include hardware identifiers that are only known to the device.
//
// Quantized time is included in order to avoid sharing stable device
// identifiers with the server. This improves privacy, since the server will
// only be able to track the device within the validity time of the identifiers
// it has collected. Once the device stops sharing identifiers, it will
// eventually regain anonymity.
class ServerBackedStateKeyGenerator {
 public:
  // Callback type for state key generation requests.
  typedef base::Callback<void(const std::vector<std::vector<uint8_t>>&)>
      StateKeyCallback;

  // The power of two determining the size of the time quanta for device state
  // keys, i.e. the quanta will be of size 2^kDeviceStateKeyTimeQuantumPower
  // seconds. 2^23 seconds corresponds to 97.09 days.
  static const int kDeviceStateKeyTimeQuantumPower = 23;

  // The number of future time quanta to generate device state identifiers for.
  // This determines the interval after which a device will no longer receive
  // server-backed state information and thus corresponds to the delay until a
  // device becomes anonymous to the server again.
  //
  // The goal here is to guarantee state key validity for 1 year into the
  // future. 4 quanta are needed to cover a year, but the current quantum is
  // clipped short in the general case. Hence, one buffer quantum is needed to
  // make up for the clipping, yielding a total of 5 quanta.
  static const int kDeviceStateKeyFutureQuanta = 5;

  ServerBackedStateKeyGenerator(SystemUtils* system_utils,
                                LoginMetrics* metrics);
  virtual ~ServerBackedStateKeyGenerator();

  // Parses a machine information string containing newline-separated key=value
  // pairs. Removes quoting from names and values. Returns true if parsing is
  // successful.
  static bool ParseMachineInfo(const std::string& data,
                               std::map<std::string, std::string>* params);

  // Sets a machine information parameters. Returns false if a parameter is
  // missing.
  bool InitMachineInfo(const std::map<std::string, std::string>& params);

  // Requests the currently-valid state keys to be computed. The state keys will
  // be returned via |callback|, potentially after waiting for machine info to
  // become available. If the state keys can't be computed due to missing
  // machine identifiers, |callback| will be invoked with an empty vector.
  void RequestStateKeys(const StateKeyCallback& callback);

 private:
  // Computes the keys and stores them in |state_keys|. In case of error,
  // |state_keys| will be cleared.
  void ComputeKeys(std::vector<std::vector<uint8_t>>* state_keys);

  SystemUtils* system_utils_;
  LoginMetrics* metrics_;

  // Pending state key generation callbacks.
  std::vector<StateKeyCallback> pending_callbacks_;

  // The data required to generate state keys.
  bool machine_info_available_;
  std::string stable_device_secret_;

  // TODO(mnissler): Remove these and the corresponding code once the old way
  // of generating state keys is no longer used in the wild, i.e. all devices
  // can be assumed to have a stable device secret.
  std::string machine_serial_number_;
  std::string disk_serial_number_;
  std::string group_code_key_;

  DISALLOW_COPY_AND_ASSIGN(ServerBackedStateKeyGenerator);
};

}  // namespace login_manager

#endif  // LOGIN_MANAGER_SERVER_BACKED_STATE_KEY_GENERATOR_H_
